package log

/* 暂时不需要，备用 */
import (
	"fmt"
	"io"
	"os"
	"path/filepath"
	"sync"
	"time"
)

/* //* 文件日志记录器实现，提供日志文件写入、目录创建、并发安全写入功能，支持文件日志的基础操作 */

/*
文件日志记录器
*/

// FileLogger 文件日志记录器，用于将日志写入指定文件
//
// ~ 字段说明：
//   - - level：当前日志级别（如LevelDebug、LevelInfo），用于过滤低级别日志
//   - - mu：互斥锁（sync.Mutex），保证多协程并发写入日志时的数据安全
//   - - writer：日志输出目标（io.Writer接口类型），此处默认指向打开的日志文件
//   - - filesource：日志文件句柄（*os.File类型），保存打开的文件实例，便于后续操作（如关闭）
//   - - path：日志文件的完整路径（字符串），记录日志文件的存储位置
type FileLogger struct {
	level  Level
	mu     sync.Mutex
	writer io.Writer
	file   *os.File
	path   string
}

/*通过writer字段兼容io.Writer接口，既支持文件输出，也可后续扩展为其他输出（如网络）；file字段单独保存文件句柄，避免丢失打开的文件实例；mu保证并发安全，防止多协程同时写入导致日志错乱*/

// NewFileLogger 创建文件日志记录器实例
//
// 参数：
//
//	level：日志级别（Level类型，如LevelDebug），决定哪些级别的日志会被记录
//	path：日志文件的完整路径（字符串，如"./logs/app.log"），指定日志存储位置
//
// 返回值：
//
//	*FileLogger：成功时返回文件日志记录器实例
//	error：失败时返回错误信息（如目录创建失败、文件打开失败）
func NewFileLogger(level Level, path string) (*FileLogger, error) {
	// 确保目录存在 确保日志文件所在的目录存在（若不存在则创建）
	dir := filepath.Dir(path)
	// os.MkdirAll(dir, 0755)：递归创建目录（若父目录不存在也会创建），0755是目录权限（所有者读/写/执行，其他读/执行）
	if err := os.MkdirAll(dir, 0755); err != nil {
		return nil, err
	}
	// 打开或创建日志文件
	// os.OpenFile参数说明：
	//   path：目标文件路径
	//*   os.O_CREATE|os.O_WRONLY|os.O_APPEND：文件打开标志（O_CREATE=不存在则创建，O_WRONLY=只写模式，O_APPEND=追加模式）
	//*   0644：文件权限（所有者读/写，其他只读）
	file, err := os.OpenFile(path, os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0644)
	if err != nil {
		return nil, err
	}
	logger := &FileLogger{
		level:  level,
		writer: file, //! 这里就初始化了写入目标
		file:   file, //& 控制文件打开关闭 权限
		path:   path,
	}
	return logger, nil
}

// 实现io.Writer 接口
func (l *FileLogger) Write(p []byte) (n int, err error) {
	l.mu.Lock()
	defer l.mu.Unlock()
	// 同时写入文件和控制台 如果配置both
	if l.writer != nil {
		return l.writer.Write(p)
	}
	return 0, nil
	//return l.writer.Write(p)
}

//

// 设置日志等级
func (l *FileLogger) SetLevel(level Level) {
	l.mu.Lock()
	defer l.mu.Unlock()
	l.level = level
}

// 获取日志级别
func (l *FileLogger) GetLevel() Level {
	l.mu.Lock()
	defer l.mu.Unlock()
	return l.level
}

// 设置日志输出 这里会设置为文件输出
func (l *FileLogger) SetOutput(w io.Writer) {
	l.mu.Lock()
	defer l.mu.Unlock()
	l.writer = w
}

// Debug 记录调试级别日志
func (l *FileLogger) Debug(args ...interface{}) {
	l.log(LevelDebug, args...)
}

// Debugf 记录调试级别日志（格式化）
func (l *FileLogger) Debugf(format string, args ...interface{}) {
	l.logf(LevelDebug, format, args...)
}

// Info 记录信息级别日志
func (l *FileLogger) Info(args ...interface{}) {
	l.log(LevelInfo, args...)
}

// Infof 记录信息级别日志（格式化）
func (l *FileLogger) Infof(format string, args ...interface{}) {
	l.logf(LevelInfo, format, args...)
}

// Warn 记录警告级别日志
func (l *FileLogger) Warn(args ...interface{}) {
	l.log(LevelWarn, args...)
}

// Warnf 记录警告级别日志（格式化）
func (l *FileLogger) Warnf(format string, args ...interface{}) {
	l.logf(LevelWarn, format, args...)
}

// Error 记录错误级别日志
func (l *FileLogger) Error(args ...interface{}) {
	l.log(LevelError, args...)
}

// Errorf 记录错误级别日志（格式化）
func (l *FileLogger) Errorf(format string, args ...interface{}) {
	l.logf(LevelError, format, args...)
}

// Fatal 记录致命错误级别日志并退出程序
func (l *FileLogger) Fatal(args ...interface{}) {
	l.log(LevelFatal, args...)
	os.Exit(1)
}

// Fatalf 记录致命错误级别日志（格式化）并退出程序
func (l *FileLogger) Fatalf(format string, args ...interface{}) {
	l.logf(LevelFatal, format, args...)
	os.Exit(1)
}

// log 记录日志
func (l *FileLogger) log(level Level, args ...interface{}) {
	if level < l.GetLevel() {
		return
	}
	message := fmt.Sprint(args...)
	l.output(level, message)
}

// 记录格式化日志
func (l *FileLogger) logf(level Level, format string, args ...interface{}) {
	if level < l.GetLevel() {
		return
	}
	message := fmt.Sprintf(format, args...)
	l.output(level, message)
}

// 输出日志
func (l *FileLogger) output(level Level, message string) {
	l.mu.Lock()
	defer l.mu.Unlock()
	timestamp := time.Now().Format("2006-01-02 15:04:05")
	logEntry := fmt.Sprintf("[%s] %s [%s] %s", LOG_PRIFIX, timestamp, level.String(), message)
	// 这里会绑定为文件句柄
	l.writer.Write([]byte(logEntry))
}

// ! Close 关闭日志文件句柄，释放文件资源（必须在程序退出前调用） 之后想想这个要在哪里使用
//
// 返回值：error - 关闭文件时可能出现的错误（如文件已关闭）
func (l *FileLogger) Close() error {
	l.mu.Lock()         // 加锁：避免关闭文件时同时有写入操作，导致 panic
	defer l.mu.Unlock() // 解锁：确保函数退出时释放锁

	// 安全检查：避免重复关闭（若file为nil或已关闭，直接返回nil）
	if l.file == nil {
		return nil
	}

	// 核心操作：调用文件句柄的Close()方法，通知操作系统释放资源
	err := l.file.Close()
	// 关闭后将file设为nil，避免后续重复调用Close()导致错误
	l.file = nil
	return err
}
